<?php
namespace monitor\client;
use phpseclib3\Crypt\PublicKeyLoader;


class SendEncryption
{
    private $publicKey;
    private $apiUrl;
    private $timeout;

    /**
     * 初始化加密客户端
     * @param string $publicKeyPath 公钥文件路径
     * @param string $apiUrl 服务端API地址
     * @param int $timeout 请求超时时间（秒）
     */
    public function __construct($publicKeyPath, $apiUrl, $timeout = 10)
    {
        $this->apiUrl = $apiUrl;
        $this->timeout = $timeout;
        // $this->loadPublicKey($publicKeyPath);
        $this->publicKey = PublicKeyLoader::load(file_get_contents($publicKeyPath))
            ->withHash('sha256')       // 主哈希算法
            ->withMGFHash('sha256');   // MGF1 哈希算法
    }

    /**
     * 加载RSA公钥
     * @param string $path 公钥文件路径
     * @throws Exception
     */
    private function loadPublicKey($path)
    {
        if (!file_exists($path)) {
            throw new Exception("公钥文件不存在: $path");
        }

        $keyContent = file_get_contents($path);
        $this->publicKey = openssl_pkey_get_public($keyContent);

        if ($this->publicKey === false) {
            throw new Exception("无效的公钥格式");
        }
    }
    function decryptData($ciphertextBase64, $aesKeyBase64, $ivBase64) {
        // 分割加密字符串为IV、密文和认证标签
        // list($ciphertextBase64, $tagBase64) = explode(':', $encrypted);
        
        // 解码Base64
        $iv = base64_decode($ivBase64);
        $ciphertext = base64_decode($ciphertextBase64);
        $aesKey = base64_decode($aesKeyBase64);
    
        // 验证解码后的密文长度是否足够分割
        if (strlen($ciphertext) < 16) {
            throw new Exception("密文长度不足16字节，无法分割出认证标签。");
        }
        
        // 分割密文：前部分为内容，后16字节为认证标签
        $tagLength = 16; // 认证标签长度（字节）
        $contentLength = strlen($ciphertext) - $tagLength;
        
        $content = substr($ciphertext, 0, $contentLength);
        $tag = substr($ciphertext, $contentLength);
    
        // 验证IV和认证标签的长度
        if (strlen($iv) !== 12) {
            throw new Exception('IV长度必须为12字节');
        }
        if (strlen($tag) !== 16) {
            throw new Exception('认证标签长度必须为16字节');
        }
    
        // 执行解密
        $plaintext = openssl_decrypt(
            $content,
            'aes-256-gcm',
            $aesKey,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );
        // if ($plaintext === false) {
        //     throw new Exception('解密失败: ' . openssl_error_string());
        // }
    
        return $plaintext;
    }
    /**
     * 生成加密载荷
     * @param mixed $data 要加密的数据
     * @return array 加密后的数据包
     */
    public function encryptData($data)
    {
        // 生成AES参数
        $aesKey = random_bytes(32); // AES-256
        $iv = random_bytes(12);     // GCM建议12字节IV

        // 加密数据
        $plaintext = is_array($data) ? json_encode($data) : $data;
        $tag = '';
        $ciphertext = openssl_encrypt(
            $plaintext,
            'aes-256-gcm',
            $aesKey,
            OPENSSL_RAW_DATA,
            $iv,
            $tag,
            '',
            16
        );

        if ($ciphertext === false) {
            throw new Exception("AES加密失败: " . openssl_error_string());
        }

        // 加密AES密钥
        $encryptedKey = $this->publicKey->encrypt($aesKey);
        return [
            'encrypted_aes_key' => base64_encode($encryptedKey),
            'encrypted_data' => base64_encode($ciphertext . $tag),
            'encrypted_iv' => base64_encode($iv),
            'aes_key' => base64_encode($aesKey)
        ];
    }

    /**
     * 发送加密请求
     * @param array $encryptedData 加密数据包
     * @return string 服务端响应
     */
    public function sendRequest($encryptedData)
    {
        $headers = [
            'X-Encrypted-AES-Key: ' . $encryptedData['encrypted_aes_key'],
            'X-Encrypted-AES-IV: ' . $encryptedData['encrypted_iv'],
            'Content-Type: application/json'
        ];

        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $this->apiUrl,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_POSTFIELDS => $encryptedData['encrypted_data'],
            CURLOPT_TIMEOUT => $this->timeout,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false // 根据实际情况调整
        ]);
        // 设置一个回调函数来捕获头部信息
        $headerSize = 0;
        $responseIV = "";
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header_line) use (&$headerSize, &$responseIV) {
            static $headers = [];
            list($key, $value) = explode(':', $header_line, 2);
            // print($key.PHP_EOL);
            if(trim($key) == "X-Encrypted-AES-IV")
            {
                $responseIV = trim($value);
            }
            // 分割头部行
            $header = rtrim($header_line, "\r\n");
            // 可以根据需要解析头部，例如按冒号分割键值对
            // 这里简单地将所有头部行存储起来
            $headers[] = $header;
            $headerSize += strlen($header_line);
            return strlen($header_line); // 返回处理过的头部行长度
        });
        
        $response = curl_exec($ch);
        if ($error = curl_error($ch)) {
            curl_close($ch);
            throw new Exception("请求失败: $error");
        }

        curl_close($ch);
        return ["body" => $response, "iv" => $responseIV];
    }
}